import { defineStore } from "pinia";
import { useUserInfoStore } from "./userInfo";
import { useIndexDB } from "./indexedDB";
import dayjs from "dayjs";

export const useSocketInfoStore = defineStore("wsInfo", {
  state: (): WS.socket => ({
    socket: null, // socket对象
    isConnent: false, // 当前websocket连接状态
    connectRetrying: 5, // 连接重试
    msg: null, // 服务端响应结果
    isWait: false, // 是否处于等待服务端响应
    curChatUser: null, // 当前选中好友信息
    pingTimeout: null, // 心跳
  }),
  getters: {
    // 初始化连接
    initWS(): Function {
      const state = this;
      const DB = useIndexDB();
      const userInfo = useUserInfoStore();
      return async (): Promise<WebSocket> =>
        await connect(
          `ws://${import.meta.env.VITE_APP_SOCKET_API}:9000`,
          state,
          DB,
          userInfo
        );
    },
    // 发送消息
    sendMsg() {
      this.isWait = true;
      return (data: WS.message) =>
        new Promise(() => {
          this.socket!.send(
            JSON.stringify({
              code: 2,
              fid: data.fid.toString(),
              chatMessage: {
                type: 1,
                tid: data.tid,
                context: data.msg,
                time: data.time,
              },
            })
          );
        });
    },
  },
  persist: true,
});

// webSocket初始化
const connect = (
  url: string,
  state: WS.socket,
  DB: { getData: Function; addOrUpdateMsg: Function },
  userInfo: {
    user: { id: number };
  }
): Promise<WebSocket> =>
  new Promise((resolve, reject) => {
    const socket = new WebSocket(url);

    // 初次连接成功后发送消息身份确认
    socket.onopen = () => {
      state.socket = socket;
      if (state.connectRetrying === 0) state.connectRetrying = 5;
      firstSendMsg(socket, userInfo.user.id);
      // 开启心跳
      state.pingTimeout = setInterval(() => {
        socket.send(JSON.stringify({ code: 3 }));
      }, 15000);
      state.isConnent = true;
    };

    //关闭
    socket.onclose = () => {
      console.warn("关闭socket");
      // 关闭心跳
      clearInterval(state.pingTimeout as number);
      state.pingTimeout = null;
      // 如果还没登陆，连接重试
      if (state.connectRetrying > 0 && !state.isConnent) {
        setTimeout(() => {
          console.warn("重试，剩余重试次数", state.connectRetrying);
          state.connectRetrying--;
          connect(url, state, DB, userInfo);
        }, 5000);
      }
      // 重试五次之后还是失败的情况
      if (state.connectRetrying === 0 && !state.isConnent) {
        reject(null);
      }
    };

    //连接发生错误的回调方法
    socket.onerror = () => {
      console.error("连接发生错误");
    };

    // 响应信息
    socket.onmessage = async (e) => {
      console.warn("服务端响应消息======>", JSON.parse(e.data));
      const res = JSON.parse(e.data);
      // 当前是否与该条消息的用户聊天
      const isCurUser = Number(state.curChatUser?.id) === Number(res.fid);
      // 更新本地缓存数据
      const DBkey = userInfo.user.id + ":" + res.fid;
      let historyData = await DB.getData(DBkey);
      const dbmsg = {
        fid: res.fid,
        tid: userInfo.user.id,
        status: isCurUser ? 1 : 0,
        msg: res.msg,
        time: dayjs(res.time).unix(),
      };
      if (historyData) {
        historyData.data.push(dbmsg);
      } else {
        historyData = {
          key: DBkey,
          data: [dbmsg],
        };
      }
      DB.addOrUpdateMsg(DBkey, historyData);

      // 如果当前登录用户在和这个用户聊天
      if (Number(state.curChatUser?.id) === Number(res.fid)) state.msg = res;
      // 初次连接成功，返回 socket对象
      resolve(socket);
    };
  });

// 初次发送消息确认连接
const firstSendMsg = (socket: WebSocket, uid: number) => {
  socket!.send(JSON.stringify({ code: 1, fid: uid }));
};

// websocket状态
// CONNECTING：值为0，表示正在连接。
// OPEN：      值为1，表示连接成功，可以通信了。
// CLOSING：   值为2，表示连接正在关闭。
// CLOSED：    值为3，表示连接已经关闭，或者打开连接失败。
